package com.gitee.ed.pattern.proxy;

import cn.hutool.core.util.ClassLoaderUtil;
import com.gitee.ed.structure.map.ClassMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Proxy;

/**
 * 代理工厂
 * 负责生成和管理动态代理实例
 *
 * @author hongda.li
 */
public final class ProxyFactory {
    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ProxyFactory.class);

    /**
     * 全局默认类加载器
     */
    private static final ClassLoader CLASS_LOADER = ClassLoaderUtil.getClassLoader();

    /**
     * 动态代理缓存，避免重复生成代理类实例
     */
    private final ClassMap proxyMap = new ClassMap();

    /**
     * 获取全部的动态代理实例缓存
     *
     * @return 动态代理缓存
     */
    public ClassMap getProxyMap() {
        return proxyMap;
    }

    /**
     * 获取代理实例
     * 若代理实例不存在则返回空
     *
     * @param interfaceClass 代理目标接口类型
     * @param <Interface>    代理目标接口泛型
     * @return 代理实例
     */
    public <Interface> Interface findProxy(final Class<Interface> interfaceClass) {
        return proxyMap.getInstance(interfaceClass);
    }

    /**
     * 创建动态代理
     * 本质调用的是 JDK 的动态代理机制
     * 因此代理目标必须是接口
     *
     * @param proxyHandler 实际的代理者
     * @param <Interface>  代理目标的类型
     * @return 代理目标的实例
     */
    public <Interface> Interface createProxy(final ProxyHandler<Interface> proxyHandler) {
        Class<Interface> target = proxyHandler.getTarget();
        Interface exists = proxyMap.getInstance(target);
        if (exists == null) {
            LOGGER.debug("Create dynamic proxy for [{}]", target.getName());
            Object instance = Proxy.newProxyInstance(CLASS_LOADER, new Class[]{target}, proxyHandler);
            proxyMap.put(target, instance);
            return target.cast(instance);
        } else {
            LOGGER.debug("Fetch dynamic proxy from cache - [{}]", target.getName());
            return exists;
        }
    }
}
